package cn.pid21.client.util;

import cn.pid21.client.exception.DataReportClientException;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.databind.*;
import com.fasterxml.jackson.dataformat.xml.XmlMapper;
import com.fasterxml.jackson.dataformat.xml.ser.ToXmlGenerator;
import org.apache.commons.lang3.StringUtils;

import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.HashMap;
import java.util.Map;
import java.util.TimeZone;

/**
 * Jackson ObjectMapper 用于生成 json/xml 工具类
 *
 * @author 李世坚
 * <b>Creation Time:</b> 2018/9/25
 */
public final class JacksonUtils {

    private ObjectMapper objectMapper;

    private static final String JSON = "json";
    private static final String XML = "xml";

    /**
     * 私有构造方法,防止实例化
     */
    private JacksonUtils(){

    }

    /**
     * 私有构造方法
     *
     * @param type json/xml
     */
    private JacksonUtils(String type) {
        if (JSON.equalsIgnoreCase(type.trim())) {
            objectMapper = new ObjectMapper();
            // 忽略json字符串中不识别的属性
            objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, true);
            // 格式化输出内容
            objectMapper.enable(SerializationFeature.INDENT_OUTPUT);
            //日期格式化
            SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd");
            objectMapper.setDateFormat(simpleDateFormat);
            //解决时区差8小时问题
            objectMapper.setTimeZone(TimeZone.getTimeZone("GMT+8"));
            // 忽略无法转换的对象 “No serializer found for class com.xxx.xxx”
            objectMapper.configure(SerializationFeature.FAIL_ON_EMPTY_BEANS, false);
            // 字段为null，自动忽略，不再序列化
            objectMapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);
            //日期格式转换
            DeserializationConfig cfg = objectMapper.getDeserializationConfig();
            cfg.with(simpleDateFormat);
            objectMapper.setConfig(cfg);
            //序列化子类时增加类名-与 redis json 序列化方式相同
            //objectMapper.enableDefaultTyping();
            //objectMapper.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);

        } else if (XML.equalsIgnoreCase(type.trim())) {
            objectMapper = new XmlMapper();
            ((XmlMapper)objectMapper).configure(ToXmlGenerator.Feature.WRITE_XML_DECLARATION, true);
            // 忽略pojo中不存在的字段
            objectMapper.configure(DeserializationFeature.FAIL_ON_IGNORED_PROPERTIES, true);
            // 格式化输出内容
            objectMapper.enable(SerializationFeature.INDENT_OUTPUT);
            //日期格式化
            SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd");
            objectMapper.setDateFormat(simpleDateFormat);
            //解决时区差8小时问题
            objectMapper.setTimeZone(TimeZone.getTimeZone("GMT+8"));
            // 字段为null，自动忽略，不再序列化
            objectMapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);
            /* 设置转换模式 */
            objectMapper.enable(MapperFeature.USE_STD_BEAN_NAMING);
            //日期格式转换
            DeserializationConfig cfg = objectMapper.getDeserializationConfig();
            cfg.with(simpleDateFormat);
            objectMapper.setConfig(cfg);

        } else {
            throw new DataReportClientException("unknown type, type is : " + type);
        }

    }

    /**
     * 获取ObjectMapper对象
     *
     * @return OJMUtils 实例
     */
    public static JacksonUtils create(String type) {
        return new JacksonUtils(type);
    }

    /**
     * JSON/XML 转换为对象
     *
     * @param str json/xml 字符串
     * @param clazz 转换类型
     * @param <T>
     * @return Object
     */
    public <T> T toObject(String str, Class<T> clazz) {
        if (StringUtils.isEmpty(str)) {
            throw new DataReportClientException("invalid string");
        }
        try {
            return objectMapper.readValue(str, clazz);
        } catch (IOException e) {
            throw new DataReportClientException("invalid Json/xml string");
        }
    }

    /**
     * 将对象转化成 JSON/XML
     *
     * @param object
     * @return String
     */
    public String convert(Object object) {
        try {
            return objectMapper.writeValueAsString(object);
        } catch (IOException e) {
            return null;
        }
    }

    /**
     * 字符串转map
     *
     * @param str
     * @return Map<String, String>
     */
    public Map<String, String> toMap(String str) {
        if (StringUtils.isEmpty(str)) {
            return new HashMap<>();
        }
        return toObject(str, Map.class);
    }

}
